<HTML>
<HEAD>
<TITLE>OpenBLT Overview</TITLE>
</HEAD>
<BODY BGCOLOR="#ffffff">

<CENTER>
<TABLE WIDTH=600>
<TR><TD>

<H1>OpenBLT: An Overview</H1>
<I>by Brian J. Swetland</I>

<P>
OpenBLT is a microkernel operating system for PC's based on the Intel
80386 or later CPUs.  Some aspects of OpenBLT were inspired by Andy
Valencia's VSTa OS, Mach, assorted UNIX variants, and the author's 
deranged imagination.  The acronym BLT expands to "Brian's Lightweight
Tasker" or "Bacon, Lettuce, and Threads".  The word Open was tacked on
for no particular reason.  
<P>
The OpenBLT kernel is responsible for managing system memory, providing
IPC facilities, and creation, destruction, and scheduling threads of control.
<P>
Below, we'll examine Tasks, Aspaces, and Ports (the basic objects managed
by the OpenBLT kernel) in terms of their use in and appearance to userland
programs.

<P><B>Tasks</B><BR>
Tasks in OpenBLT are single threads of control.  Each task is associated
with an address space, within which it runs.  Tasks may terminate themselves
using the 
<PRE>void  os_terminate(int status);</PRE>
system call.  A task may start another task (sharing the same address space)
using the

<PRE>int   os_thread(void *addr);</PRE>
system call.  The new task begins execution at the specified address and
a 4K stack is created for it.  <I>[ os_thread() will probably take a stack
pointer address in the next revision ]</I>

<P><B>Address Spaces</B><BR>
Address spaces are currently not readily manipulated from userland.  
In the near future, shared memory system calls should allow the creation
of new address spaces and sharing memory between address spaces.  A
thread may request that its address space be expanded using the <TT>os_brk()</TT> system call:
<PRE>
int   os_brk(int addr);
</PRE>

<P><B>Ports</B><BR>
IPC (interprocess communication) in OpenBLT occurs when one task sends a
message to another task via a port.  Ports are 'owned' by one task (the
task that created them).  Messages are send from one port to another port
(thus a port must exist for the sending task to send from).  A port may
be restricted so that it can only receive messages from one specified
other port <I>[ future versions will likely allow a list of allowed senders ]</I>.


<P>
All messages sent or received via an OpenBLT port are described with
a message header.  The header indicates the source port, destination port,
size of message, pointer to message data (or receive data buffer), and
flags (to allow for future expansion -- non-blocking IO, scatter/gather
IO, etc)
<PRE>
typedef struct {
    int flags;
    int src;
    int dst;
    int size;
    void *data;    
} msg_hdr_t;
</PRE>


<P><TT>int <B>port_create</B>(uint32 restrict);</TT><BR>
Create a new port owned by the running thread.  Only allow messages
from port 'restrict' to be received.  If <TT>restrict</TT> is 0, messages
from any source will be received.  Will return <TT>ERR_MEMORY</TT> if
the system lacks the resources to create the port, otherwise the port
number will be returned.

<P><TT>int <B>port_destroy</B>(uint32 port);</TT><BR>
Destroy an existing port.  Returns <TT>ERR_RESOURCE</TT> if <TT>port</TT> is
not a valid port or if there are other ports slaved to this port.
Returns <TT>ERR_PERMISSION</TT> if the running thread is not the owner
of this port.  Returns <TT>ERR_NONE</TT> upon success/

<P><TT>int <B>port_send</B>(msg_hdr_t *mh);</TT></BR>
Send the message in <TT>mh->data</TT>, of length <TT>mh->size</TT>
from port <T>mh->src</TT> to port <TT>mh->dst</TT>.  Returns
<TT>mh->size</TT> upon success, <TT>ERR_MEMORY</TT> if there is a
bounds error, <TT>ERR_RESOURCE</TT> if either the source or
destination ports do not exist, <TT>ERR_PERMISSION</TT> if the source
is not owned by the running thread or the destination is not sendable
from the source port.

<P><TT>int <B>port_recv</B>(msg_hdr_t *mh);</TT></BR>
Receive a message (in buffer <TT>mh->data</TT>, max length
<TT>mh->size</TT>) from port <TT>mh->dst</TT>.  Upon success,
<TT>mh->src</TT> will be set to the sender, <TT>mh->dst</TT> will be
set to the destination if it was a slaved port, and the number of
received bytes will be returned.  If the data or header are out of
bounds, <TT>ERR_MEMORY</TT> is returned.  If the destination port does
not exist <TT>ERR_RESOURCE</TT> is returned.  If the running thread
does not own the destination port, <TT>ERR_PERMISSION</TT> is
returned.  This call will block if no messages are available, unless
the port is set to NOWAIT, in which case <TT>ERR_WOULDBLOCK</TT> is
returned.

<P><TT>int <B>port_option</B>(uint32 port, int opt, int arg);</TT></BR>
Modify port options.  The two functions below are wrappers around 
<TT>port_option()</TT>

<P><TT>int <B>port_slave</B>(uint32 master, uint32 slave);</TT><BR>
Cause the master port to receive all messages sent to the slave port.
If master is 0, the slave is released from bondage.  Returns ERR_NONE
upon success, <TT>ERR_PERMISSION</TT> if the master and slave are not
both owned by the running thread, or <TT>ERR_RESOURCE</TT> if the
master or slave are not valid ports.

<P><TT>int <B>port_set_restrict</B>(uint32 port, uint32 restrict);</TT><BR>
Change the restriction on a port.  Returns <TT>ERR_NONE</TT> on
success, <TT>ERR_RESOURCE</TT> if the port does not exits, or
<TT>ERR_PERMISSION</TT> if the running thread does not own the port.
A restriction of 0 allows any port to send to this port.

<P><B>Finding other tasks to talk to</B><BR>
Since port numbers are generated dynamically by the kernel and tend to
be different depending on the order tasks are started, etc, there needs
to be a mechanism for locating device drivers or just other tasks to 
talk to.  The kernel automatically creates port 1 (the uberport) and gives
ownership of this port to the first task created.  This task is the namer,
a service that allows drivers to register ports under specific names and
allows tasks that wish to find these drivers to look up the port that is
associated with a specific name.
<P>
The utility functions listed below are part of the OpenBLT libc and provide
convenient ways to access the namer.
<PRE>
int namer_newhandle(void);
int namer_delhandle(int nh);
int namer_register(int nh, int port, char *name);
int namer_find(int nh, char *name);
</PRE>

<P><B>Connections between Connectionless ports</B><BR>
Ports in OpenBLT are connectionless.  Each <TT>port_send()</TT> specifies
a source and destination port.  Tasks may send from any port they own to
any port they are allowed to write to.  Ports may be writable to be any
other port or restricted to just one other port. <I>[ multiple port restrict
lists will be in a later version ]</I>
<P>
The general procedure for providing a service in OpenBLT is
<UL>
<LI>Create an unrestricted port
<LI>Register this port with the namer under a descriptive name (eg ne2000, console, etc)
</UL>
When one task (a client) wishes to connect to a service (the server), 
the following occurs:
<UL>
<LI>The client looks up the servers unrestricted port using the namer
<LI>The client creates a port that is restricted to the server's 
unrestricted port
<LI>The client sends a message to the servers unrestricted port 
requesting a connection
<LI>If the server accepts the connection, it will send a response back 
to the client's port notifying it that the connection is accepted and
 possibly providing a different port than the unrestricted port that the
client should send future messages too.
</UL>
<I>[ a toolkit in libc will streamline this process ]</I>

<P><B>Handling Devices</B><BR>
The security model in OpenBLT is still being designed.  Most likely
there will be a task that is a "security manager" which will be able
to give permissions (for accession IO devices, etc) to tasks that need them.
The two syscalls described below are sufficient for simple device drivers
in the initial (overly trusting) version of OpenBLT:

<P><TT>void  <B>os_handle_irq</B>(int irq);</TT><BR>
Ask the kernel to make this task eligible to process the specified IRQ.
The kernel will also allow the task IO access.


<P><TT>void  <B>os_sleep_irq</B>(void);</TT><BR>
Suspend this task until the IRQ it is registered to handle is triggered.
When that IRQ is triggered, the task will be scheduled (preempting the
currently running task).  The IRQ will be ignored by the kernel when the
task is no sleeping in <TT>os_sleep_irq()</TT>.

<P><B>Startup</B><BR>
On startup, OpenBLT creates initializes its internal memory and resource
management, sets up kernel space at the 2gb line (0x8000000), creates
an address space and task for each userland program that it can find.
An idle task is created (to give the scheduler something to schedule, 
should all other tasks be sleeping on something). The kernel schedules
the first task in the run queue to execute and the fun starts.


</TD></TR>
</TABLE>
</CENTER>

</BODY>
